#ifndef ACTION_ATTACK_H_INCLUDED
#define ACTION_ATTACK_H_INCLUDED

struct combatant;
struct map_location;
class team;
class unit;
class unit_map;

#include "../unit_types.hpp"

#include <vector>

inline unsigned swarm_blows(unsigned min_blows, unsigned max_blows, unsigned hp,
							unsigned max_hp)
{
	return hp >= max_hp ? max_blows :
		max_blows < min_blows ? min_blows - (min_blows - max_blows) * hp / max_hp :
								min_blows + (max_blows - min_blows) * hp / max_hp;
}

struct battle_context_unit_stats
{
	const attack_type* weapon;
	int attack_num;
	bool is_attacker;
	bool is_poisoned;
	bool is_slowed;
	bool slows;
	bool drains;
	bool petrifies;
	bool plagues;
	bool poisons;
	bool backstab_pos;

	bool swarm;
	bool firststrike;
	unsigned int experience, max_experience;
	unsigned int level;

	unsigned int rounds;
	unsigned int hp;
	unsigned int max_hp;
	unsigned int chance_to_hit;
	int damage;
	int slow_damage;
	int drain_percent;
	int drain_constant;
	unsigned int num_blows;
	unsigned int swarm_min;
	unsigned int swarm_max;

	std::string plague_type;

	battle_context_unit_stats(const unit& u, const map_location& u_loc,
		int u_attack_num, bool attacking,
		const unit& opp, const map_location& opp_loc,
		const attack_type* opp_weapon,
		const unit_map& units);
	~battle_context_unit_stats()
	{}

	unsigned int calc_blows(unsigned new_hp) const
	{return swarm_blows(swarm_min, swarm_max, new_hp, max_hp);}

#if defined(BENCHMARK) || defined(CHECK)
	battle_context_unit_stats(int dmg, int blows, int hitpoints, int maximum_hp,
							 int hit_chance, bool drain, bool slows, bool slowed,
							 bool berserk, bool first, bool do_swarm) :
	weapon(NULL), attack_num(0), is_attacker(true),
	is_poisoned(false), is_slowed(slowed),
	slows(slows), drains(drain), petrifies(false), plagues(false),
	poisons(false), backstrap_pos(false), swarm(do_swarm), firststrike(first),
	experience(0), max_experience(50), level(1),
	rounds(berserk ? 30 : 1),
	hp(std::max<int>(0, hitpoints)), max_hp(std::max<int>(1, maximum_hp)),
	chance_to_hit(hit_chance),
	damage(std::max(0, dmg)), slow_damage(round_damage(damage, 1, 2)),
	drain_percent(drain ? 50 : 0), drain_constant(0),
	num_blows(do_swarm ? blows * hp / max_hp : blows),
	swarm_min(do_swarm ? 0 : blows), swarm_max(blows),
	plague_type()
	{
		if (slowed)
			damaged = slow_damage;
		if (hp > max_hp)
			hp = max_hp;
	}
#endif
};

class battle_context
{
public:
	battle_context(const unit_map& units,
				   const map_location& attacker_loc, const map_location& defender_loc,
				   int attacker_weapon = -1, int defender_weapon = -1,
				   double aggression = 0.0, const combatant* prev_def = NULL,
				   const unit* attacker_ptr = NULL);

	battle_context(const battle_context_unit_stats& att, const battle_context_unit_stats& def);

	battle_context(const battle_context& other);
	~battle_context();

	battle_context& operator=(const battle_context& other);

	const battle_context_unit_stats& get_attacker_stats() const {return *attacker_stats_;}

	const battle_context_unit_stats& get_defender_stats() const {return *defender_stats_;}

	const combatant& get_attacker_combatant(const combatant* prev_def = NULL);
	const combatant& get_defender_combatant(const combatant* prev_def = NULL);

	bool better_attack(class battle_context& that, double harm_weight);

private:
	bool better_combat(const combatant& us_a, const combatant& them_a,
					   const combatant& us_b, const combatant& them_b,
					   double harm_weight);


	int choose_attacker_weapon(const unit& attacker, const unit& defender,
							   const unit_map& units,
							   const map_location& attacker_loc, const map_location& defender_loc,
							   double harm_weight, int* defender_weapon,
							   const combatant* prev_def);

	int choose_defender_weapon(const unit& attacker, const unit& defender,
							   unsigned attacker_weapon, const unit_map& units,
							   const map_location& attacker_loc,
							   const map_location& defender_loc,
							   const combatant* prev_def);

	battle_context_unit_stats *attacker_stats_, *defender_stats_;

	combatant *attacker_combatant_, *defender_combatant_;
};

void attack_unit(const map_location& attacker, const map_location& defender,
				int attack_with, int defend_with, bool update_display = true);

unit get_advanced_unit(const unit& u, const std::string& advance_to);

unit get_amla_unit(const unit& u, const config& mod_option);

void advance_unit(map_location loc, const std::string& advance_to,
				  const bool& fire_event = true, const config* mod_option = NULL);

map_location under_leadership(const unit_map& units, const map_location& loc,
							  int* bonus = NULL);

int combat_modifier(const map_location& loc, unit_type::ALIGNMENT alignment,
					bool is_fearless);

bool backstab_check(const map_location& attacker_loc,
					const map_location& defender_loc,
					const unit_map& units, const std::vector<team>& teams);

#endif 
